import { RefProp, useCall, useMountedRef, useRaf, useSimpleMemo, useWillMountEffect } from '@/components';
import { FORM_ITEM_KEYS } from '@/constants/componentKeys';
import { defaultShouldUpdate, getReturn, pick } from '@/utils';
import { Form } from 'antd';
import React, { useEffect, useRef } from 'react';

function FieldEffect({ value, pubsub, shouldUpdate = defaultShouldUpdate, ...rest }) {
  const ref = useRef();
  const fieldProps = useSimpleMemo(pick(rest, FORM_ITEM_KEYS)[0]);
  const isUpdate = useRef(false);
  const mountedRef = useMountedRef();

  function until(isDone, callback) {
    if (!mountedRef.current) return;
    setTimeout(() => {
      if (isDone()) callback();
      else until(isDone, callback);
    });
  }

  // 从 pubsub 更新
  useWillMountEffect(pubsub?.sub, async (subValue) => {
    if (ref.current) {
      const [currValue, onChange] = ref.current;
      if (await getReturn(shouldUpdate(currValue, subValue))) {
        isUpdate.current = true;
        onChange?.(subValue);
        until(
          () => ref.current?.[0] === subValue,
          () => {
            isUpdate.current = false;
          },
        );
      }
    }
  });

  const updateFromValue = useCall(async (refCurrent) => {
    if (!refCurrent) return;
    const [currValue, onChange] = refCurrent;
    if (typeof value !== 'undefined' && (await getReturn(shouldUpdate(currValue, value)))) {
      if (typeof pubsub?.update === 'function') {
        pubsub.update(value);
      } else {
        onChange?.(value);
      }
    }
  }, ref);

  useWillMountEffect(updateFromValue);

  // 从 value 更新
  useEffect(() => {
    updateFromValue();
  }, [value]);

  // 获取 value 绑定到 pubsub
  useRaf(async () => {
    if (isUpdate.current) return;
    if (ref.current && pubsub) {
      const [currValue] = ref.current;
      if (await getReturn(shouldUpdate(pubsub.value, currValue))) {
        pubsub.update(currValue);
      }
    }
  });

  return (
    <Form.Item {...fieldProps} className='hidden'>
      <RefProp ref={ref} refKey={['value', 'onChange']} />
    </Form.Item>
  );
}

export default FieldEffect;
